<!DOCTYPE html>
<html lang="en">
    <!---
https://cdn.bootcdn.net/ajax/libs/three.js/0.166.1/three.module.js
比如安装148版本
npm install three@0.148.0 save
-->

    <head>
        <meta charset="UTF-8">
        <title>cube</title>
        <script type="importmap">
        {
          "imports": {
            "three": "./js/threejs/three.module.js",
            "three/addons/": "./js/jsm/"
          }
        }
    </script>
        <style>
        body {
            margin: 0;
            background-color: #000;
            color: #fff;
            font-family: Monospace;
            font-size: 13px;
            line-height: 24px;
            overscroll-behavior: none;
        }

        canvas {
            display: block;
        }

        #tooltip {
            position: absolute;
            background-color: rgba(0, 0, 0, 0.7);
            color: white;
            padding: 5px;
            border-radius: 5px;
            display: none;
            /* 默认隐藏 */
            pointer-events: none;
            font-size: 12px;
            white-space: break-spaces;
            z-index: 1;
        }
    </style>
    </head>

    <body>
        <!-- 创建用于显示提示的文本元素 -->
        <div id="container"></div>
        <div id="tooltip" onclick="tooltipCkick"></div>
        <script type="module">
        import * as THREE from "./js/threejs/three.module.js";
        import { OrbitControls } from './js/threejs/jsm/controls/OrbitControls.js';

        const indices = [
            0, 1, 2, 0, 2, 3,   // 下面
            4, 5, 6, 4, 6, 7,   // 上面
            // 4, 0, 1, 4, 1, 5,
            8, 9, 10, 8, 10, 11,   // 前面
            12, 13, 14, 12, 14, 15,   // 后面
            16, 17, 18, 16, 18, 19,   // 左面
            20, 21, 22, 20, 22, 23    // 右面
        ]

        const uvs = new Float32Array([
            0,0,1,0,1,1,0,1,  // 下面 0,6
            0,0,1,0,1,1,0,1,
            0,0,1,0,1,1,0,1,  // 前面 12,6
            0,0,1,0,1,1,0,1,  // 后面 18,6
            0,0,1,0,1,1,0,1,  // 左面 24,6
            0,0,1,0,1,1,0,1,   // 右面 30,6
        ]);

        var scene, camera, renderer, container;
        var raycaster = new THREE.Raycaster();
        var pointer = new THREE.Vector2();

        initScene();
        render();


        var gOptArry = [
            {
                faceIdx: 0,  //填充面序号
                size: [
                    { postion: [{ x: 0, y: 0 }, { x: 200, y: 100 }], pic: './img/p01.png', title: 'p01' },
                    { postion: [{ x: 200, y: 0 }, { x: 200, y: 100 }], pic: './img/p02.png', title: 'p02' },
                    { postion: [{ x: 0, y: 100 }, { x: 200, y: 100 }], pic: './img/p03.png', title: 'p03' },
                    { postion: [{ x: 200, y: 100 }, { x: 200, y: 100 }], pic: './img/p04.png', title: 'p04' },
                    { postion: [{ x: 400, y: 0 }, { x: 100, y: 100 }], color: '#8833ff', title: '#8833ff' },
                    { postion: [{ x: 400, y: 100 }, { x: 100, y: 100 }], color: '#ff3333', title: '#ff3333' }
                ]
            },
            {
                faceIdx: 1,  //填充面序号
                size: [
                    { postion: [{ x: 0, y: 0 }, { x: 200, y: 100 }], pic: './img/p01.png', title: 'p01' },
                    { postion: [{ x: 200, y: 0 }, { x: 200, y: 100 }], pic: './img/p04.png', title: 'p04' },
                    { postion: [{ x: 0, y: 100 }, { x: 200, y: 100 }], pic: './img/p03.png', title: 'p03' },
                    { postion: [{ x: 200, y: 100 }, { x: 200, y: 100 }], pic: './img/p02.png', title: 'p02' },
                    { postion: [{ x: 400, y: 0 }, { x: 100, y: 100 }], color: '#ff3333', title: '#ff3333' },
                    { postion: [{ x: 400, y: 100 }, { x: 100, y: 100 }], color: '#8833ff', title: '#8833ff' }
                ]
            },
            {
                faceIdx: 2,  //填充面序号
                size: [
                    { postion: [{ x: 0, y: 0 }, { x: 200, y: 100 }], pic: './img/p01.png', title: 'p01' },
                    { postion: [{ x: 200, y: 0 }, { x: 200, y: 100 }], pic: './img/p04.png', title: 'p04' },
                    { postion: [{ x: 0, y: 100 }, { x: 200, y: 100 }], pic: './img/p03.png', title: 'p03' },
                    { postion: [{ x: 200, y: 100 }, { x: 200, y: 100 }], pic: './img/p02.png', title: 'p02' },
                    { postion: [{ x: 400, y: 0 }, { x: 100, y: 100 }], color: '#ff3333', title: '#ff3333' },
                    { postion: [{ x: 400, y: 100 }, { x: 100, y: 100 }], color: '#8833ff', title: '#8833ff' }
                ]
            },
            {
                faceIdx: 3,  //填充面序号
                size: [
                    { postion: [{ x: 0, y: 0 }, { x: 200, y: 100 }], pic: './img/p01.png', title: 'p01' },
                    { postion: [{ x: 200, y: 0 }, { x: 200, y: 100 }], pic: './img/p04.png', title: 'p04' },
                    { postion: [{ x: 0, y: 100 }, { x: 200, y: 100 }], pic: './img/p03.png', title: 'p03' },
                    { postion: [{ x: 200, y: 100 }, { x: 200, y: 100 }], pic: './img/p02.png', title: 'p02' },
                    { postion: [{ x: 400, y: 0 }, { x: 100, y: 100 }], color: '#ff3333', title: '#ff3333' },
                    { postion: [{ x: 400, y: 100 }, { x: 100, y: 100 }], color: '#8833ff', title: '#8833ff' }
                ]
            },
            {
                faceIdx: 4,  //填充面序号
                size: [
                    { postion: [{ x: 0, y: 0 }, { x: 200, y: 100 }], pic: './img/p01.png', title: 'p01' },
                    { postion: [{ x: 200, y: 0 }, { x: 200, y: 100 }], pic: './img/p04.png', title: 'p04' },
                    { postion: [{ x: 0, y: 100 }, { x: 200, y: 100 }], pic: './img/p03.png', title: 'p03' },
                    { postion: [{ x: 200, y: 100 }, { x: 200, y: 100 }], pic: './img/p02.png', title: 'p02' },
                    { postion: [{ x: 400, y: 0 }, { x: 100, y: 100 }], color: '#ff3333', title: '#ff3333' },
                    { postion: [{ x: 400, y: 100 }, { x: 100, y: 100 }], color: '#8833ff', title: '#8833ff' }
                ]
            },
            {
                faceIdx: 5,  //填充面序号
                size: [
                    { postion: [{ x: 0, y: 0 }, { x: 200, y: 100 }], pic: './img/p01.png', title: 'p01' },
                    { postion: [{ x: 200, y: 0 }, { x: 200, y: 100 }], pic: './img/p04.png', title: 'p04' },
                    { postion: [{ x: 0, y: 100 }, { x: 200, y: 100 }], pic: './img/p03.png', title: 'p03' },
                    { postion: [{ x: 200, y: 100 }, { x: 200, y: 100 }], pic: './img/p02.png', title: 'p02' },
                    { postion: [{ x: 400, y: 0 }, { x: 100, y: 100 }], color: '#ff3333', title: '#ff3333' },
                    { postion: [{ x: 400, y: 100 }, { x: 100, y: 100 }], color: '#8833ff', title: '#8833ff' }
                ]
            }
        ];
        let optparams = {
            size: { x: 540, y: 240, z: 240 }
        };
        createCube(optparams, gOptArry);

        function createCube(optparams, optArry) {
            let ldrawnum = 0;
            var material2 = new THREE.MeshPhongMaterial({ color: 0xffffff, side: THREE.DoubleSide });
            var groups = [
                {
                    "start": 0,
                    "count": 6,
                    "materialIndex": 0
                },
                {
                    "start": 6,
                    "count": 6,
                    "materialIndex": 1
                },
                {
                    "start": 12,
                    "count": 6,
                    "materialIndex": 2
                },
                {
                    "start": 18,
                    "count": 6,
                    "materialIndex": 3
                },
                {
                    "start": 24,
                    "count": 6,
                    "materialIndex": 4
                },
                {
                    "start": 30,
                    "count": 6,
                    "materialIndex": 5
                }
            ];
            let materials = [material2, material2, material2, material2, material2, material2];
            if (optparams === undefined || optparams === null) optparams = {};
            let params = JSON.parse(JSON.stringify(optparams));
            let ratio = 1;
            if (params.ratio) ratio = params.ratio;
            let vWidth = params.hasOwnProperty("size") ? params["size"].x : 128;
            let vheight = params.hasOwnProperty("size") ? params["size"].z : 64;

            function finish(eparam, faceUdata, lcontext, lcanvas) {
                faceUdata.drawnum++;
                if (faceUdata.drawnum >= faceUdata.drawtotal) {

                    ldrawnum++;
                    lcontext.scale(ratio, ratio);

                    let texture = new THREE.Texture(lcanvas);
                    texture.needsUpdate = true;//, color: 0xff00ff, fog: true
                    // for (let index = 0; index < materials.length; index++) {
                    //     materials[index] = new THREE.MeshPhongMaterial({ map: texture, side: THREE.DoubleSide });
                    // }
                    materials[faceUdata.faceIdx] = new THREE.MeshPhongMaterial({ map: texture, side: THREE.DoubleSide });
                    if (ldrawnum >= optArry.length) {
                        let geometry = new THREE.BoxGeometry(vWidth, vheight, params.size.y);
                        // let geometry = new THREE.BoxGeometry(1, 1, 1);
                        // const mesh = new THREE.Mesh(geometry, materials);

                        const vertices = getCubeFaces(optparams.size.x, optparams.size.y, optparams.size.z)
                        const doorGeometry = new THREE.BufferGeometry();
                        doorGeometry.setAttribute("position", new THREE.BufferAttribute(new Float32Array(vertices), 3));
                        doorGeometry.setIndex(indices);
                        doorGeometry.setAttribute('uv', new THREE.BufferAttribute(uvs, 2))
                        doorGeometry.computeVertexNormals()
                        const mesh = new THREE.Mesh(doorGeometry, materials);
                        doorGeometry.groups = groups

                        console.warn(geometry, doorGeometry)
                        // mesh.geometry.groups = groups;
                        scene.add(mesh);
                    }
                }
            }

            let optItem, faceItem;
            for (let i = 0; i < optArry.length; i++) {
                optItem = optArry[i];

                let lcanvas = document.createElement('canvas');
                lcanvas.width = vWidth * ratio;
                lcanvas.height = vheight * ratio;
                lcanvas.style.width = vWidth + 'px';
                lcanvas.style.height = vheight + 'px';
                let lcontext = lcanvas.getContext('2d');

                lcontext.clearRect(0, 0, vWidth, vheight);
                lcontext.fillStyle = "rgba(255,255,255,1)";
                lcontext.fillRect(0, 0, vWidth, vheight);

                let faceUdata = {
                    drawnum: 0,
                    faceIdx: optItem.faceIdx,
                    drawtotal: optItem.size.length
                }
                for (let j = 0; j < optItem.size.length; j++) {
                    faceItem = optItem.size[j];

                    fillImg(lcontext, lcanvas, faceItem, faceUdata, ratio, finish);
                }

            }
        }

        function fillImg(lcontext, lcanvas, params, type, ratio, callback) {
            var _this = this;
            let imgurl = params.hasOwnProperty("pic") ? params["pic"] : "";
            let x = params.postion[0].x, y = params.postion[0].y;
            let width = params.postion[1].x, height = params.postion[1].y;

            if (imgurl != undefined && imgurl != null && imgurl != '') {

                try {
                    let vImg = new Image();
                    vImg.src = imgurl;
                    const loader = new THREE.ImageLoader();
                    loader.load(imgurl,
                        function (image) {
                            lcontext.drawImage(image, x, y, width, height);
                            callback(params, type, lcontext, lcanvas);
                        },
                        undefined,
                        function () {
                            console.error('An error happened.');
                            callback(params, type, lcontext, lcanvas);
                        }
                    );

                } catch (err) {
                    console.log(err);
                }
            } else {
                var vbkColor = params.hasOwnProperty("color") ? params["color"] : { r: 255, g: 255, b: 255, a: 1.0 };
                // let crgba = hexToRgb(vbkColor).rgb;
                lcontext.fillStyle = vbkColor;
                lcontext.fillRect(x, y, width, height);
                callback(params, type, lcontext, lcanvas);
            }
            document.body.append(lcanvas)
        }

        function getDatetime() {
            const now = new Date();

            const year = now.getFullYear();
            const month = ('0' + (now.getMonth() + 1)).slice(-2);
            const day = ('0' + now.getDate()).slice(-2);
            const hours = ('0' + now.getHours()).slice(-2);
            const minutes = ('0' + now.getMinutes()).slice(-2);
            const seconds = ('0' + now.getSeconds()).slice(-2);

            const formattedTime = year + month + day + ' ' + hours + ':' + minutes + ':' + seconds;

            return formattedTime;
        }

        //初始化场景
        function initScene() {
            // 创建场景
            scene = new THREE.Scene();
            scene.background = new THREE.Color(0x000000)

            container = document.getElementById('container');
            // 创建相机
            camera = new THREE.PerspectiveCamera(90, window.innerWidth / window.innerHeight, 0.1, 10000);
            // camera.position.x = 300;
            camera.position.y = -300;
            camera.position.z = 400;

            // 创建渲染器
            renderer = new THREE.WebGLRenderer({ antialias: true });
            // 渲染器能够渲染阴影效果
            renderer.shadowMap.enabled = true;
            renderer.setSize(window.innerWidth, window.innerHeight);
            container.appendChild(renderer.domElement);


            // 添加网格辅助器
            const gridHelper = new THREE.GridHelper(5000, 50); // 创建一个200单位的网格，细分为50个方格
            gridHelper.rotation.x = 0.5 * Math.PI
            // gridHelper.position.y = -150;
            scene.add(gridHelper);

            // 添加 XYZ 坐标轴 (红: X, 绿: Y, 蓝: Z)
            const axesHelper = new THREE.AxesHelper(550); // 参数表示轴的长度
            scene.add(axesHelper);

            // 方向光
            const directionalLight = new THREE.DirectionalLight(0xFFFFFF, 1);
            directionalLight.position.set(10, 10, 10);

            directionalLight.shadow.mapSize.width = 1024  // default
            directionalLight.shadow.mapSize.height = 1024  // default
            directionalLight.shadow.camera.near = 0.05  // default
            directionalLight.shadow.camera.far = 500  // default
            //将范围调大
            directionalLight.shadow.camera.top = 20 /// 这个是生效的属性
            directionalLight.shadow.camera.right = 20
            directionalLight.shadow.camera.left = -20
            directionalLight.shadow.camera.bottom = -20
            directionalLight.castShadow = true;
            scene.add(directionalLight);

            // 环境光
            const ambientLight = new THREE.AmbientLight(0xffffff, 2);
            scene.add(ambientLight);

            // 添加鼠标控制
            const controls = new OrbitControls(camera, renderer.domElement);
            // controls.enableDamping = true; // 使得相机移动更加平滑
            controls.dampingFactor = 0.05; // 阻尼效果

            window.addEventListener('pointerup', onPointerUp);
            window.addEventListener('resize', onWindowResize, false);
        }

        function onPointerUp(event) {

            // 将鼠标位置归一化为设备坐标。x 和 y 方向的取值范围是 (-1 to +1)

            pointer.x = (event.clientX / window.innerWidth) * 2 - 1;
            pointer.y = - (event.clientY / window.innerHeight) * 2 + 1;

            raycaster.setFromCamera(pointer, camera);

            // 计算物体和射线的焦点
            const intersects = raycaster.intersectObjects(scene.children);
            if (intersects.length > 0) {
                let intersectObj = intersects[0];
                if (intersectObj.uv) {
                    let optItem, faceItem, bcheck = false;

                    let uvx = intersectObj.uv.x * optparams.size.x;
                    let uvy = (1 - intersectObj.uv.y) * optparams.size.y;

                    for (let i = 0; i < gOptArry.length; i++) {
                        optItem = gOptArry[i];

                        if (optItem.faceIdx == intersectObj.face.materialIndex) {

                            for (let j = 0; j < optItem.size.length; j++) {
                                faceItem = optItem.size[j];
                                if (faceItem.postion[0].x <= uvx && faceItem.postion[0].y <= uvy &&
                                    (faceItem.postion[0].x + faceItem.postion[1].x) >= uvx && (faceItem.postion[0].y + faceItem.postion[1].y) >= uvy) {
                                    bcheck = true;
                                    // console.log('拾取第' + (i + 1) + '图片');
                                    alert(faceItem.title);
                                    break;
                                }
                            }

                        }
                    }

                    if (!bcheck) {
                        alert(getDatetime());
                    }
                }
            }

        }

        function getCubeFaces(length, width, height) {
            // 立方体的8个顶点
            const vertices = [
                [0, 0, 0],
                [length, 0, 0],
                [length, width, 0],
                [0, width, 0],
                [0, 0, height],
                [length, 0, height],
                [length, width, height],
                [0, width, height]
            ];

            // 每个面的顶点（顺时针或逆时针）
            const faces = [
                // 底面
                [0, 1, 2, 3],
                // 顶面
                [4, 5, 6, 7],
                // 前面
                [0, 1, 5, 4],
                // 后面
                [2, 3, 7, 6],
                // 左面
                [0, 3, 7, 4],
                // 右面
                [1, 2, 6, 5]
            ];

            // 生成顶点数组
            const facesVertices = [];
            faces.forEach(face => {
                face.forEach(index => {
                    facesVertices.push(...vertices[index]);
                });
            });

            return facesVertices;
        }

        function onWindowResize() {

            camera.aspect = window.innerWidth / window.innerHeight;
            camera.updateProjectionMatrix();

            renderer.setSize(window.innerWidth, window.innerHeight);

        }

        function render() {
            // 渲染
            requestAnimationFrame(render);
            renderer.render(scene, camera);
        }

    </script>

    </body>

</html>